package netWork

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"go-web-learning/src/02_message_system/02_message_system/chatroom/common/message"
	"io"
	"net"
)

type Conn struct {
	net.Conn
	Msg message.Message
}

func (c *Conn) SetMsg(msg message.Message) {
	c.Msg = msg
}

func (c *Conn) Send() (n int, err error) {
	msgBytes, err := c.Msg.ToJsonBytes()
	if err == nil {
		n, err = c.sendLen(msgBytes)
		if err == nil {
			n, err = c.sendMsg(msgBytes)
			//fmt.Printf("发送数据长度：%d，内容：%s\n", len(msgBytes), string(msgBytes))
		}
	}
	return
}

func (c *Conn) Get() (msg message.Message, err error) {
	buf := make([]byte, 1024*8)
	// 只有conn有效时，才会阻塞
	_, err = c.Read(buf[:4])
	if err != nil {
		if err != io.EOF {
			err = errors.New(fmt.Sprintf("read Header err: %v", err))
		}
		return
	}
	var pkgLen uint32
	pkgLen = binary.BigEndian.Uint32(buf[:4])
	n, err := c.Read(buf[:pkgLen])
	if n != int(pkgLen) {
		err = errors.New(fmt.Sprintf("read Body err: not all read [%v]", n))
		return
	} else if err != nil {
		err = errors.New(fmt.Sprintf("read Header err: %v", err))
		return
	}
	err = json.Unmarshal(buf[:pkgLen], &msg)
	if err != nil {
		err = errors.New(fmt.Sprintf("unmarshal err: %v", err))
		return
	}
	return
}

func (c *Conn) sendLen(msg []byte) (n int, err error) {
	var msgLen = uint32(len(msg))
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[:], msgLen)
	n, err = c.Write(buf[:])
	return
}

func (c *Conn) sendMsg(msg []byte) (n int, err error) {
	n, err = c.Write(msg)
	return
}

type Listener struct {
	net.Listener
}

func (l *Listener) Accept() (Conn, error) {
	conn, err := l.Listener.Accept()
	if err != nil {
		return Conn{}, err
	}
	return Conn{Conn: conn}, nil

}

func Dial(network, address string) (Conn, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		fmt.Println("net dial err:", err)
		return Conn{}, err
	}
	return Conn{Conn: conn}, err
}

func Listen(network, address string) (Listener, error) {
	listen, err := net.Listen(network, address)
	if err != nil {
		fmt.Println("net listen err:", err)
		return Listener{}, err
	}
	return Listener{listen}, nil
}
